package com.example.yx.demo17;

import org.aopalliance.intercept.MethodInterceptor;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.support.GenericApplicationContext;

public class A17 {
    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("aspect1",Aspect1.class);
        context.registerBean("config",Config.class);
        context.registerBean(ConfigurationClassPostProcessor.class);

        //AnnotationAwareAspectJ：识别切面注解、AutoProxyCreator：自动创建代理
        //它实现了BeanPostProcessor接口，
        //创建 -> (情况1：在此处创建代理)依赖注入 -> 初始化:情况2：在此处创建代理) -> 销毁
        context.registerBean(AnnotationAwareAspectJAutoProxyCreator.class);

        /*
        AnnotationAwareAspectJAutoProxyCreator有两个重要的方法：
            1.间接继承自AbstractAdvisorAutoProxyCreator的List<Advisor> findEligibleAdvisors，意为找到有资格的advisor
                a.有 【资格】 的advisor，一部分是低级的，由自己编写，如例子的advisor3
                b.有 【资格】 的advisor，另一部分是高级的，由解析@Aspect后获得
            2.wrapIfNecessary，是否有必要为目标创建代理
                a.内部调用findEligibleAdvisors，只要返回的集合不为空，就说明需要创建代理（需要功能增强）
         */


        context.refresh();
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }

        context.close();

    }

    static class T1{
        public void foo() {
            System.out.println("target1 foo");
        }
    }

    static class T2{
        public void bar() {
            System.out.println("target2 bar");
        }
    }

    @Aspect//高级切面类
    static class Aspect1 {
        @Before("execution(* foo())")
        public void before() {
            System.out.println("before....");
        }

        @After("execution(* foo())")
        public void after(){
            System.out.println("after...");
        }
    }

    @Configuration
    static class Config{
        @Bean//低级切面
        public Advisor advisor3(MethodInterceptor advice3) {
            AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
            pointcut.setExpression("execution(* foo())");
            return new DefaultPointcutAdvisor(pointcut,advice3);
        }

        @Bean
        public MethodInterceptor advice3() {
            return invocation -> {
                System.out.println("advice3 before...");
                Object result = invocation.proceed();
                System.out.println("advice after...");
                return result;
            };

        }
    }
}
